home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / icmpcmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-14  |  8.5 KB  |  367 lines

  1. /* ICMP-related user commands
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  */
  4.  /* Mods by PA0GRI */
  5. #include <stdio.h>
  6. #include <time.h>
  7. #include "global.h"
  8. #include "icmp.h"
  9. #include "ip.h"
  10. #include "mbuf.h"
  11. #include "netuser.h"
  12. #include "internet.h"
  13. #include "timer.h"
  14. #include "socket.h"
  15. #include "proc.h"
  16. #include "session.h"
  17. #include "cmdparse.h"
  18. #include "commands.h"
  19.  
  20. static int doicmpec __ARGS((int argc, char *argv[],void *p));
  21. static int doicmpstat __ARGS((int argc, char *argv[],void *p));
  22. static int doicmptr __ARGS((int argc, char *argv[],void *p));
  23. static void pingtx __ARGS((int s,void *ping1,void *p));
  24. static void pinghdr __ARGS((struct session *sp,struct ping *ping,time_t *start));
  25.  
  26. int currentPing;
  27.  
  28. static struct cmds Icmpcmds[] = {
  29.     "echo",         doicmpec,       0, 0, NULLCHAR,
  30.     "status",       doicmpstat,     0, 0, NULLCHAR,
  31.     "trace",        doicmptr,       0, 0, NULLCHAR,
  32.     NULLCHAR
  33. };
  34.  
  35. int Icmp_trace;
  36. static int Icmp_echo = 1;
  37.  
  38. int
  39. doicmp(argc,argv,p)
  40. int argc;
  41. char *argv[];
  42. void *p;
  43. {
  44.     return subcmd(Icmpcmds,argc,argv,p);
  45. }
  46.  
  47. static int
  48. doicmpstat(argc,argv,p)
  49. int argc;
  50. char *argv[];
  51. void *p;
  52. {
  53.     register int i;
  54.     int lim;
  55.  
  56.     /* Note that the ICMP variables are shown in column order, because
  57.      * that lines up the In and Out variables on the same line
  58.      */
  59.     lim = NUMICMPMIB/2;
  60.     for(i=1;i<=lim;i++){
  61.         tprintf("(%2u)%-20s%10lu",i,Icmp_mib[i].name,
  62.          Icmp_mib[i].value.integer);
  63.         tprintf("     (%2u)%-20s%10lu\n",i+lim,Icmp_mib[i+lim].name,
  64.          Icmp_mib[i+lim].value.integer);
  65.     }
  66.     return 0;
  67. }
  68.  
  69. static int
  70. doicmptr(argc,argv,p)
  71. int argc;
  72. char *argv[];
  73. void *p;
  74. {
  75.     if(argc < 2) {
  76.         tprintf("ICMP Tracing is %d\n",Icmp_trace) ;
  77.         return 0 ;
  78.     }
  79.     
  80.     switch(argv[1][0]) {
  81.         case '0':
  82.         case '1':
  83.         case '2': Icmp_trace=atoi(argv[1]);
  84.             break;
  85.         default:
  86.             tprintf("Trace modes are: 0|1|2\n") ;
  87.             return -1 ;
  88.     }
  89.  
  90.     return 0 ;
  91. }
  92.  
  93. static int
  94. doicmpec(argc,argv,p)
  95. int argc;
  96. char *argv[];
  97. void *p;
  98. {
  99.     return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
  100. }
  101.  
  102. /* Send ICMP Echo Request packets */
  103. static int
  104. pingcmd(argc,argv,p)
  105. int argc;
  106. char *argv[];
  107. void *p;
  108. {
  109. struct proc *pinger = NULLPROC; /* Transmit process */
  110. struct sockaddr_in from;
  111. struct icmp icmp;
  112. struct mbuf *bp;
  113. int32 timestamp,rtt,abserr;
  114. int s,fromlen;
  115. struct ping ping;
  116. struct session *sp;
  117. time_t starttime, thetime;
  118. char *cptr;
  119. int usesession = 0;
  120.  
  121.     /* Make sure this is a 'one-shot- ping
  122.      * if not coming from the console - WG7J
  123.      */
  124.     if(argc > 3)
  125.     if(Curproc->input != Command->input)
  126.         return 0;
  127.  
  128.     memset((char *)&ping,0,sizeof(ping));
  129.     /* Allocate a session descriptor if this comes from console */
  130.     if(Curproc->input == Command->input) {
  131.         usesession = 1;
  132.     if((sp = ping.sp = newsession(argv[1],PING,0)) == NULLSESSION){
  133.         tputs(TooManySessions);
  134.         return 1;
  135.     }
  136.     }
  137.     if((sp->s = s = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  138.         tputs(Nosock);
  139.             if(usesession) {
  140.             keywait(NULLCHAR,1);
  141.             freesession(sp);
  142.         }
  143.         return 1;
  144.     }
  145.     tprintf("Resolving %s... ",argv[1]);
  146.     if((ping.target = resolve(argv[1])) == 0){
  147.         tprintf(Badhost,argv[1]);
  148.             if(usesession) {
  149.             keywait(NULLCHAR,1);
  150.             freesession(sp);
  151.         }
  152.         return 1;
  153.     }
  154.     if(argc > 2)
  155.         ping.len = atoi(argv[2]);
  156.  
  157.     if(argc > 3)
  158.         ping.interval = atol(argv[3]);
  159.  
  160.  
  161.     /* Optionally ping a range of IP addresses */
  162.     if(argc > 4)
  163.         ping.incflag = 1;
  164.  
  165.     if(ping.interval != 0){
  166.         pinger = newproc("pingtx",300,pingtx,s,&ping,NULL,0);
  167.     } else {
  168.         /* One shot ping; let echo_proc hook handle response.
  169.          * An ID of MAXINT16 will not be confused with a legal socket
  170.          * number, which is used to identify repeated pings
  171.          */
  172.             if(usesession)    {
  173.             pingem(s,ping.target,0,MAXINT16,ping.len);
  174.             freesession(sp);
  175.         } else    {
  176.             int k;
  177.             tprintf("Pinging %s... Press <CR> to abort...\n",argv[1]);
  178.             usflush(Curproc->output);
  179.             currentPing = Curproc->output;
  180.             pingem(s,ping.target,0,MAXINT16,ping.len);
  181.             for (k = 0; k < 120; k++)    {
  182.                 if (!currentPing)
  183.                     break;
  184.                 if(socklen(Curproc->input,0))    {
  185.                     recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0); /* flush */
  186.                     tprintf ("%s: ping aborted by user after %d seconds\n", argv[1], k);
  187.                     break;
  188.                 }
  189.                 mspause(1000L);
  190.             }
  191.             currentPing = 0;
  192.             if (k == 120)
  193.                 tprintf ("%s: no response after 120 seconds\n", argv[1]);
  194.         }
  195.         return 0;
  196.     }
  197.     time (&starttime);
  198.     /* Now collect the replies */
  199.     pinghdr(sp,&ping,&starttime);
  200.     for(;;){
  201.         fromlen = sizeof(from);
  202.         if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1)
  203.             break;
  204.         ntohicmp(&icmp,&bp);
  205.         if(icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s){
  206.             /* Ignore other people's responses */
  207.             free_p(bp);
  208.             continue;
  209.         }
  210.         /* Get stamp */
  211.         if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
  212.          != sizeof(timestamp)){
  213.             /* The timestamp is missing! */
  214.             free_p(bp);     /* Probably not necessary */
  215.             continue;
  216.         }
  217.         free_p(bp);
  218.  
  219.         ping.responses++;
  220.  
  221.         /* Compute round trip time, update smoothed estimates */
  222.         rtt = msclock() - timestamp;
  223.         abserr = (rtt > ping.srtt) ? (rtt-ping.srtt) : (ping.srtt-rtt);
  224.  
  225.         if(ping.responses == 1){
  226.             /* First response, base entire SRTT on it */
  227.             ping.srtt = rtt;
  228.             ping.mdev = 0;
  229.         } else {
  230.             ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
  231.             ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
  232.         }
  233.         if((ping.responses % 20) == 0)
  234.             pinghdr(sp,&ping, &starttime);
  235.         time (&thetime);
  236.         cptr = ctime(&thetime);
  237.         tprintf("%10lu%10lu%5lu%10lu%10lu%10lu     %8.8s\n",
  238.          ping.sent,ping.responses,
  239.          (ping.responses*100 + ping.sent/2)/ping.sent,
  240.          rtt,ping.srtt,ping.mdev, &cptr[11]);
  241.     }
  242.     if(pinger != NULLPROC)
  243.         killproc(pinger);
  244.     freesession(sp);
  245.     return 0;
  246. }
  247.  
  248. int
  249. doping(argc,argv,p)
  250. int argc;
  251. char *argv[];
  252. void *p;
  253. {
  254.     char **pargv;
  255.     int i;
  256.  
  257.     if(Curproc->input == Command->input) {
  258.         /* Make private copy of argv and args,
  259.          * spawn off subprocess and return.
  260.          */
  261.         pargv = (char **)callocw(argc + 1,sizeof(char *));
  262.         for(i=0;i<argc;i++)
  263.             pargv[i] = strdup(argv[i]);
  264.         pargv[i] = NULL;
  265.         newproc("ping",512,(void (*)())pingcmd,argc,(void *)pargv,p,1);
  266.     } else
  267.         pingcmd(argc,argv,p);
  268.     return 0;
  269. }
  270.  
  271.  
  272. static void
  273. pinghdr(sp,ping, start)
  274. struct session *sp;
  275. struct ping *ping;
  276. time_t *start;
  277. {
  278.     tprintf("Pinging %s (%s); data %d interval %lu ms:\n    since %s",
  279.      sp->name,inet_ntoa(ping->target),ping->len,ping->interval, ctime(start));
  280.     tprintf("      sent      rcvd    %%       rtt   avg rtt      mdev     received\n");
  281. }
  282.  
  283. void
  284. echo_proc(source,dest,icmp,bp)
  285. int32 source;
  286. int32 dest;
  287. struct icmp *icmp;
  288. struct mbuf *bp;
  289. {
  290.     int32 timestamp,rtt;
  291.  
  292.     if(Icmp_echo && icmp->args.echo.id == MAXINT16
  293.      && pullup(&bp,(char *)×tamp,sizeof(timestamp))
  294.      == sizeof(timestamp)){
  295.         /* Compute round trip time */
  296.         rtt = msclock() - timestamp;
  297.         usprintf((currentPing) ? currentPing : Curproc->output, "%s: rtt %lu\n",inet_ntoa(source),rtt);
  298.         currentPing = 0;
  299.     }
  300.     free_p(bp);
  301. }
  302. /* Ping transmit process. Runs until killed */
  303. static void
  304. pingtx(s,ping1,p)
  305. int s;          /* Socket to use */
  306. void *ping1;
  307. void *p;
  308. {
  309.     struct ping *ping;
  310.  
  311.     ping = (struct ping *)ping1;
  312.     ping->sent = 0;
  313.     if(ping->incflag){
  314.         for(;;){
  315.             pingem(s,ping->target++,0,MAXINT16,ping->len);
  316.             ping->sent++;
  317.             mspause(ping->interval);
  318.         }
  319.     } else {
  320.         for(;;){
  321.             pingem(s,ping->target,(int16)ping->sent++,(int16)s,ping->len);
  322.             mspause(ping->interval);
  323.         }
  324.     }
  325. }
  326.  
  327.  
  328. /* Send ICMP Echo Request packet */
  329. int
  330. pingem(s,target,seq,id,len)
  331. int s;          /* Raw socket on which to send ping */
  332. int32 target;   /* Site to be pinged */
  333. int16 seq;      /* ICMP Echo Request sequence number */
  334. int16 id;       /* ICMP Echo Request ID */
  335. int16 len;      /* Length of optional data field */
  336. {
  337.     struct mbuf *data;
  338.     struct mbuf *bp;
  339.     struct icmp icmp;
  340.     struct sockaddr_in to;
  341.     int32 clock;
  342.  
  343.     clock = msclock();
  344.     data = ambufw((int16)(len+sizeof(clock)));
  345.     data->cnt = len+sizeof(clock);
  346.     /* Set optional data field, if any, to all 55's */
  347.     if(len != 0)
  348.         memset(data->data+sizeof(clock),0x55,len);
  349.  
  350.     /* Insert timestamp and build ICMP header */
  351.     memcpy(data->data,(char *)&clock,sizeof(clock));
  352.     icmpOutEchos++;
  353.     icmpOutMsgs++;
  354.     icmp.type = ICMP_ECHO;
  355.     icmp.code = 0;
  356.     icmp.args.echo.seq = seq;
  357.     icmp.args.echo.id = id;
  358.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  359.         free_p(data);
  360.         return 0;
  361.     }
  362.     to.sin_family = AF_INET;
  363.     to.sin_addr.s_addr = target;
  364.     send_mbuf(s,bp,0,(char *)&to,sizeof(to));
  365.     return 0;
  366. }
  367.